package com.mjlf.framework.aop;

import com.mjlf.framework.annotation.aop.After;
import com.mjlf.framework.annotation.aop.Before;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * @auther a123
 * @create 2018-08-30 16:49
 * @desc 增强工具类, 在使用这个类中needProxy方法进行判断方法是否需要代理之前，必须先加载所有的增强方法
 * AdviseMethodManager 类中定义了加载所有增强的方法
 */
public final class AdviseUtil {

    public static boolean needProxy(Method method) {
        Set<Annotation> adviseAnnotations = AdviseMethodManager.PROXY_METHOD.keySet();
        if (adviseAnnotations != null) {
            for (Annotation annotation : adviseAnnotations) {
                if(parseMethodProxy(annotation, method)){
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean parseMethodProxy(Annotation annotation, Method method){
        String modifier = Modifier.toString(method.getModifiers());
        Class returnType = method.getReturnType();
        String name = method.getDeclaringClass().getName() + "." + method.getName();
        Class<?>[] paramsClass = method.getParameterTypes();
        if (annotation instanceof Before) {
            Before before = (Before) annotation;
            if (!before.modifier().equals(modifier)) {
                return false;
            }
            if (before.returnType() != returnType && before.returnType() != After.class) {
                return false;
            }
            String adviseName = before.value();
            if(!parseMethodName(adviseName, name)){
                return false;
            }
            Class[] args = before.args();
            if(args.length == 1 && args[0] == Before.class){
                return true;
            }
            if(paramsClass.length != args.length){
                return false;
            }
            for(int i = 0; i < args.length; i++){
                if(args[i] != paramsClass[i]){
                    return false;
                }
            }
            return true;
        }else if (annotation instanceof After) {
            After after = (After) annotation;
            if (!after.modifier().equals(modifier)) {
                return false;
            }
            if (after.returnType() != returnType && after.returnType() != After.class) {
                return false;
            }
            String adviseName = after.value();
            if(!parseMethodName(adviseName, name)){
                return false;
            }
            Class[] args = after.args();
            if(args.length == 1 && args[0] == Before.class){
                return true;
            }
            if(paramsClass.length != args.length){
                return false;
            }
            for(int i = 0; i < args.length; i++){
                if(args[i] != paramsClass[i]){
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 判断指定方法是否与指定的增强类型匹配
     * @param adviseName
     */
    public static boolean parseMethodName(String adviseName, String methodName) {
        String[] txts = adviseName.split("(\\.)");
        String reg = "^";
        for (int i = 0; i < txts.length; i++) {
            String t = txts[i];
            if ("".equals(t)) {
                reg += "(\\w*\\.)*";
            } else if ("*".equals(t)) {
                if (i == txts.length - 1) {
                    reg += "(\\w+){1}";
                } else {
                    reg += "(\\w+\\.){1}";
                }
            } else {
                if (t.contains("*")) {
                    t = t.replaceAll("\\*", "\\\\w*");
                }
                if (i == txts.length - 1) {
                    reg += t;
                } else {
                    reg += t + "\\.";
                }
            }
        }
        if (reg.lastIndexOf(".") == reg.length() - 1) {
            reg = reg.substring(0, reg.length() - 2);
        }
//        System.out.println("regex : " + reg);
//        System.out.println("methodName : " + methodName);

        Pattern r = Pattern.compile(reg);
        return r.matcher(methodName).matches();
    }
}
